package agenda;

import java.util.Date;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Timer;

public abstract class Entry implements Timeable {

	protected static Timer timer = new Timer(true);
	private Notification notification;
	private Agenda<?> agenda;
	private int day;
	private String subject;

	protected Entry(Agenda<?> agenda, int day, String subject) {
		assert (agenda != null);
		this.agenda = agenda;
		setDay(day);
		if (subject == null)
			subject = "";
		setSubject(subject);
		if (this instanceof Occupiable) {
			resetNotification();
		}
	}

	private void resetNotification() {
		if(this.notification != null)
			notification.cancel();
		this.notification = new Notification(this);
		timer.schedule(notification, new Date(this.getStartTime() - 15 * 60 * 1000));
	}

	public boolean canHaveAsDay(int day) {
		return (day >= 0);
	}

	@Override
	public boolean endsAfter(Timeable other) {
		return (other != null) && (this.getEndTime() >= other.getEndTime());
	}

	public Agenda<?> getAgenda() {
		return this.agenda;
	}

	public int getDay() {
		return this.day;
	}

	@Override
	public long getStartTime() {
		// We assume that day 0, slot 1 corresponds to January 1, 2011.
		Calendar referenceDate = new GregorianCalendar(2011, Calendar.JANUARY,
				1);
		return referenceDate.getTimeInMillis() + this.getDay() * 24 * 60 * 60
				* 1000;
	}

	public String getSubject() {
		return this.subject;
	}

	public boolean isTerminated() {
		return getAgenda() == null;
	}

	public abstract Entry mergeWith(final Entry other);

	public abstract boolean overlapsWith(Entry other);

	public void setDay(int day) {
		if (!isTerminated()) {
			if (canHaveAsDay(day))
				this.day = day;
			else if (getDay() == 0)
				this.day = 1;
		}
		resetNotification();
	}

	public void setSubject(String subject) {
		assert (subject != null);
		this.subject = subject;
	}

	@Override
	public boolean startsBefore(Timeable other) {
		return (other != null) && (this.getStartTime() <= other.getStartTime());
	}

	public void terminate() {
		Agenda<?> oldAgenda = this.agenda;
		this.agenda = null;
		oldAgenda.removeEntry(this);
	}

	public void shift(int days) {
		int newDay = this.getDay() + days;
		if (newDay < 0) {
			newDay = 0;
		}
		this.setDay(newDay);
		resetNotification();
	}

}
